import 'package:dio/dio.dart';
import 'package:flutter_blog_manage_study/http/http_exception.dart';
import 'package:flutter_blog_manage_study/http/request_api.dart';
import 'package:connectivity/connectivity.dart';

typedef Success<T> = Function(T data);
typedef Fail = Function(int code, String msg);

/// * 作者: Tao
/// * 日期: 2024/3/20
/// * 时间: 14:16
/// * 描述: Dio基础请求封装
class HttpRequest {
  /// token
  static const String _token = '';

  /// 全局Dio
  static Dio? _dio;

  static Dio createInstance([bool isJson = true]) {
    if (_dio == null) {
      var options = BaseOptions(
        ///提交方式：1.表单提交 2.JSON方式提交
        /// 请求的Content-Type，默认值是"application/json; charset=utf-8".
        /// 如果您想以"application/x-www-form-urlencoded"格式编码请求数据,
        /// 可以设置此选项为 `Headers.formUrlEncodedContentType`,  这样[Dio]就会自动编码请求体.
        contentType: isJson
            ? Headers.jsonContentType
            : Headers.formUrlEncodedContentType,
        validateStatus: (status) {
          /// 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
          return true;
        },
        baseUrl: RequestApi.baseurl,

        /// 发送超时时间
        sendTimeout: const Duration(seconds: 10),

        /// 连接超时时间
        connectTimeout: const Duration(seconds: 10),

        /// 接收超时时间
        receiveTimeout: const Duration(seconds: 10),
      );
      _dio = Dio(options)
        ..interceptors  /// 添加请求日志拦截器
            .add(LogInterceptor(responseBody: true, requestBody: true));
    }
    _dio?.options.contentType =
        isJson ? Headers.jsonContentType : Headers.formUrlEncodedContentType;
    return _dio!;
  }

  /// 请求
  /// * [method] 请求类型
  /// * [path] 请求地址
  /// * [params] 请求参数
  /// * [isJson] 是否是json提交
  /// * [success] 请求成功回调
  /// * [fail] 请求失败回调
  static Future request<T>(
    Method method,
    String path,
    dynamic params, {
    bool isJson = true,
    Success? success,
    Fail? fail,
  }) async {
    try {
      /// 检查网络
      var result = await (Connectivity().checkConnectivity());
      if (result == ConnectivityResult.none) {
        _onError(HttpException.netError, '网络异常，请检查你的网络', fail);
        return;
      }
      Dio dio = createInstance(isJson);
      Response response = await dio.request(path,
          data: params,
          options: Options(
            method: _methodValues[method],
            // headers: _headerToken(),
          ));
      if (success != null) {
        success(response.data);
      }
    } on DioException catch (e) {
      final NetError netError = HttpException.handlerException(e);
      _onError(netError.code, netError.msg, fail);
    }
  }
}

/// 错误处理
/// * [code] 错误码
/// * [msg] 错误信息
/// * [fail] 错误回调
void _onError(int code, String msg, Fail? fail) {
  if (code == 0) {
    code = HttpException.unknownError;
    msg = '未知异常';
  }
  if (fail != null) {
    fail(code, msg);
  }
}

enum Method {
  GET,
  POST,
  PUT,
  DELETE,
  PATCH,
  HEAD,
  DOWNLOAD,
  UPLOAD,
}

const _methodValues = {
  Method.GET: 'get',
  Method.POST: 'post',
  Method.PUT: 'put',
  Method.DELETE: 'delete',
  Method.PATCH: 'patch',
  Method.HEAD: 'head',
  Method.DOWNLOAD: 'download',
  Method.UPLOAD: 'upload',
};
